package cn.org.wangchangjiu.redis.springcache;

import cn.org.wangchangjiu.redis.util.StringRedisTemplateSliceUtils;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * @author wangchangjiu
 * @Classname RediSetCacheKeySaver
 * @Description
 * @Date 2024/8/23 17:47
 */
public class RedisSetCacheKeySaver implements CacheKeySaver {

    private final StringRedisTemplateSliceUtils redisTemplateSliceUtils;

    private final StringRedisTemplate stringRedisTemplate;

    private final Map<String, Integer> bucketMap;

    private final static Integer DEFAULT_BUCKET_NUMBER = 5000;

    private static final String REDIS_BUCKET_CACHE_KEY = "cacheKey:%s";


    public RedisSetCacheKeySaver(StringRedisTemplateSliceUtils redisTemplateSliceUtils, StringRedisTemplate stringRedisTemplate, Map<String, Integer> bucketMap){
        this.redisTemplateSliceUtils = redisTemplateSliceUtils;
        this.stringRedisTemplate = stringRedisTemplate;
        this.bucketMap = bucketMap;

    }

    @Override
    public void putKey(String name, String key) {
        // 假如 key : YES,NORMAL,DANGER,HIGH_RISK_262144_android_hitv1128_es_DO
        // name: cms:more_ranking
        // 分片存储 set 存储桶信息
        //  cacheKey:name  key  key
        Integer BUCKET_NUMBER = bucketMap.getOrDefault(name, DEFAULT_BUCKET_NUMBER);

        String zoneKey = "cache:" + name + ":%s:{cs}";
        String redisKey = redisTemplateSliceUtils.sliceKeyWrapper(zoneKey, key, BUCKET_NUMBER);
        redisTemplateSliceUtils.setAdd(zoneKey, key, BUCKET_NUMBER);

        stringRedisTemplate.opsForSet().add(String.format(REDIS_BUCKET_CACHE_KEY, name), redisKey);
    }

    @Override
    public KeyResult getKey(String name) {

        // 获取所有的桶
        String redisBucketCacheKey = String.format(REDIS_BUCKET_CACHE_KEY, name);
        List<String> keys = stringRedisTemplate.opsForSet().pop(redisBucketCacheKey, stringRedisTemplate.opsForSet().size(redisBucketCacheKey));
        if(CollectionUtils.isEmpty(keys)){
            return KeyResult.empty();
        }

        RedisSerializer keySerializer = stringRedisTemplate.getKeySerializer();
        RedisSerializer valueSerializer = stringRedisTemplate.getValueSerializer();

        List<Object> allRedisKey = stringRedisTemplate.executePipelined((RedisCallback<Object>) connection -> {
            keys.stream().forEach(key -> {
                byte[] rawKey = keySerializer.serialize(key);
                connection.setCommands().sPop(rawKey, Integer.MAX_VALUE);
            });
            return null;
        }, valueSerializer);


        if(CollectionUtils.isEmpty(allRedisKey)){
            return KeyResult.empty();
        }

        List<String> allKeys = new ArrayList<>();
        allRedisKey.stream().forEach(item -> {
            if(item instanceof Collection){
                allKeys.addAll(Collection.class.cast(item));
            }
        });
        return KeyResult.all(allKeys);
    }
}
